﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using VASJ.Model;



namespace VASJ.Service.Library.Manager
{
    public class RoleManager : BaseManager
    {
        /// <summary>
        /// Init
        /// </summary>
        /// <param name="_ApplicationName"></param>
        public RoleManager(string _ApplicationName)
            : base(_ApplicationName)
        {
        }

        /// <summary>
        /// Get RoleID by RoleName
        /// </summary>
        /// <returns></returns>
        public Guid GetRoleID(string roleName)
        {
            try
            {
                Guid RoleID = Guid.Empty;

                var role = from it in this.mdb.AHSAspnetRoles
                           where it.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower() && it.Rolename == roleName
                           select it.Roleid;

                if (role != null && role.Count() > 0)
                {
                    RoleID = role.FirstOrDefault();
                }

                return RoleID;
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] RoleManager.GetRoleID {0}", ex);

                return Guid.Empty;
            }
        }

        /// <summary>
        /// Author: Hoang Van Tai
        /// Get role for user (for Pisara)
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public string[] GetRolesForUserPS(string userName)
        {
            try
            {
                List<string> roles = new List<string>();
                List<string> roleforproject = new List<string>();

                //Get all role available for project
                var rfps = from rfp in this.mdb.AHSAspnetRoles
                           where rfp.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()
                           select new { Rolename = rfp.Rolename };

                foreach (var it in rfps)
                {
                    roleforproject.Add(it.ToString());
                }

                //Check role in system
                List<string> roleinsystem = Roles.Provider.GetRolesForUser(userName).ToList();

                foreach (var it in roleinsystem)
                {
                    if (roleforproject.Contains(it)) roles.Add(it);
                }

                var query = (from uip in this.mdb.AHSUserInProjects
                             where ((uip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()) && (uip.AHSAspnetMembership_Userid.AHSAspnetUser.Username.ToLower() == userName.ToLower()) && (uip.Status.HasValue) && (uip.Status.Value == 1) && (uip.Roleid.HasValue))
                             select new { Rolename = uip.AHSAspnetRole.Rolename }
                            ).Union(from oip in this.mdb.AHSOrganizationInProjects
                                    join uio in this.mdb.AHSUsersInOrganizations on oip.Orgid equals uio.OrgId
                                    where ((oip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()) && (uio.AHSAspnetUser.Username.ToLower() == userName.ToLower())
                                    && (oip.Status.HasValue) && (oip.Status.Value == 1) && (uio.Status.HasValue && uio.Status.Value == 1) && (oip.Roleid.HasValue))
                                    select new { Rolename = oip.AHSAspnetRole.Rolename }
                            ).Union(from rio in this.mdb.AHSUsersInOrganizations
                                    where (rio.AHSAspnetUser.Username.ToLower() == userName.ToLower()) && (rio.AHSOrganization.OrgType == 1) && (rio.Status.HasValue && rio.Status.Value == 1) && (rio.AHSOrganization.RoleID.HasValue)
                                    select new { Rolename = rio.AHSOrganization.AHSAspnetRole.Rolename }
                            );

                foreach (var item in query)
                {
                    if (!roles.Contains(item.Rolename)) roles.Add(item.Rolename);
                }

                return roles.ToArray();
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] RoleManager.GetRolesForUserPS {0}", ex);

                return null;
            }
        }

        /// <summary>
        /// Get role for user in application
        /// </summary>
        /// <param name="userName"></param>
        /// <returns></returns>
        public string[] GetRolesForUser(string userName)
        {
            try
            {
                List<string> roles = new List<string>();
                List<string> roleforproject = new List<string>();
                List<string> retRoles = new List<string>();

                //Get all role available for project
                var rfps = from rfp in this.mdb.AHSAspnetRoles
                           where rfp.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()
                           select rfp;

                foreach (var it in rfps)
                {
                    roleforproject.Add(it.Rolename);
                }

                //Check role in system
                List<string> roleinsystem = Roles.Provider.GetRolesForUser(userName).ToList();

                foreach (var it in roleinsystem)
                {
                    if (roleforproject.Contains(it)) roles.Add(it);
                }

                //Check role user in project
                var uips = from uip in this.mdb.AHSUserInProjects
                           where uip.Status.HasValue && uip.Status.Value == 1 && uip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower() && uip.AHSAspnetMembership_Userid.AHSAspnetUser.Username.ToLower() == userName.ToLower() && uip.Roleid.HasValue
                           select uip.AHSAspnetRole.Rolename;

                foreach (var uip in uips)
                {
                    if (!roles.Contains(uip)) roles.Add(uip);
                }

                //Check role user in project via organization
                var oips = from oip in this.mdb.AHSOrganizationInProjects
                           join uio in this.mdb.AHSUsersInOrganizations on oip.Orgid equals uio.OrgId
                           where oip.Status.HasValue && oip.Status.Value == 1 && uio.Status.HasValue && uio.Status.Value == 1
                           && oip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()
                           && uio.AHSAspnetUser.Username.ToLower() == userName.ToLower()
                           && oip.Roleid.HasValue
                           select oip.AHSAspnetRole.Rolename;

                foreach (var oip in oips)
                {
                    if (!roles.Contains(oip)) roles.Add(oip);
                }

                //Check role user in organ empowering
                var rios = from rio in this.mdb.AHSUsersInOrganizations
                           where rio.Status.HasValue && rio.Status.Value == 1 && rio.AHSAspnetUser.Username.ToLower() == userName.ToLower() && rio.AHSOrganization.OrgType == 1 && rio.AHSOrganization.RoleID.HasValue
                           select rio.AHSOrganization.AHSAspnetRole.Rolename;

                foreach (var rio in rios)
                {
                    if (!roles.Contains(rio) && roleforproject.Contains(rio)) roles.Add(rio);
                }

                var get_roles = from gr in this.mdb.AHSAspnetRoles
                                where roles.Contains(gr.Rolename)
                                orderby gr.Priority descending, gr.Rolename ascending
                                select gr.Rolename;
                foreach (var r in get_roles)
                {
                    retRoles.Add(r);
                }

                return retRoles.ToArray();
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] RoleManager.GetRolesForUser {0}", ex);

                return null;
            }
        }

        /// <summary>
        /// Get role for user in project and application 
        /// </summary>
        /// <param name="projectId"></param>
        /// <param name="userName"></param>
        /// <returns></returns>
        public string[] GetRolesForUser(int projectId, string username)
        {
            try
            {
                List<string> roles = new List<string>();
                
                //Check role user in project
                var uips = from uip in this.mdb.AHSUserInProjects
                           where (uip.Status.HasValue && uip.Status.Value == 1) && (uip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()) &&  
                           (uip.AHSAspnetMembership_Userid.AHSAspnetUser.Username.ToLower() == username.ToLower()) && (uip.Roleid.HasValue) && (uip.Projectid == projectId)
                           select new { RoleName = uip.AHSAspnetRole.Rolename};

                foreach (var item in uips)
                {
                    roles.Add(item.RoleName);
                }

                //Check role user in project via organization
                var oips = from oip in this.mdb.AHSOrganizationInProjects
                           join uio in this.mdb.AHSUsersInOrganizations on oip.Orgid equals uio.OrgId
                           where (oip.Status.HasValue && oip.Status.Value == 1) && (uio.Status.HasValue && uio.Status.Value == 1) 
                           && (oip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower())
                           && (uio.AHSAspnetUser.Username.ToLower() == username.ToLower()) && (oip.Roleid.HasValue) && (oip.Projectid == projectId)
                           select new { RoleName = oip.AHSAspnetRole.Rolename};

                foreach (var item in oips)
                {
                    if (!roles.Contains(item.RoleName)) roles.Add(item.RoleName);
                }

                return roles.ToArray();
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] RoleManager.GetRolesForUser error {0}", ex);

                return null;
            }
        }

        /// <summary>
        /// Author: Hoang Van Tai
        /// </summary>
        /// <param name="userName"></param>
        /// <param name="projectID"></param>
        /// <returns></returns>
        /// Add:Hoang Van Tai
        /// Modify:
        public bool IsPermitUserForUser(string PermitName, string username)
        {
            // Check user is IsPermitUser
            try
            {
                bool ret = false;

                var query = (from uip in this.mdb.AHSUserInProjects
                             where (uip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == PermitName.ToLower()) && (uip.AHSAspnetMembership_Userid.AHSAspnetUser.Username.ToLower() == username.ToLower())
                             && uip.AHSAspnetRole.Adminforprojectype.HasValue && uip.AHSAspnetRole.AHSProjectType_Adminforprojectype.ApplicationName.ToLower() == this.ApplicationName.ToLower()
                             select new { userid = uip.Userid, IsPermitUser = uip.AHSAspnetRole.Isrolepermit, uip.AHSAspnetRole.Adminforprojectype }).Distinct();

                if (query != null)
                {
                    foreach (var role in query)
                    {
                        ret = role.IsPermitUser == null ? false : true;

                        if (ret) break;
                    }
                }

                return ret;
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] RoleManager.IsPermitUserForUser {0}", ex);

                return false;
            }
        }

        /// <summary>
        /// Get All role for application
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllRoles()
        {
            try
            {
                List<string> roles = new List<string>();

                var pts = from pt in this.mdb.AHSAspnetRoles
                          where pt.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower() && (!pt.Isrolepermit.HasValue || !pt.Isrolepermit.Value)
                          orderby pt.Priority.Value descending, pt.Rolename ascending
                          select new { pt.Rolename, pt.Priority };

                foreach (var pt in pts)
                {
                    roles.Add(pt.Rolename);
                }

                return roles;
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] RoleManager.GetAllRoles {0}", ex);

                return null;
            }
        }

        /// <summary>
        /// Get All role for application and project type
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllRolesForProjectType(string projectTypeName)
        {
            try
            {
                List<string> roles = new List<string>();

                var pts = from pt in this.mdb.AHSAspnetRoles
                          where pt.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower() && pt.AHSProjectType.Name == projectTypeName && (!pt.Isrolepermit.HasValue || !pt.Isrolepermit.Value)
                          orderby pt.Priority.Value descending, pt.Rolename ascending
                          select pt.Rolename;

                foreach (var pt in pts)
                {
                    roles.Add(pt);
                }

                return roles;
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] RoleManager.GetAllRoles {0}", ex);

                return null;
            }
        }

        /// <summary>
        /// Author: Phong
        /// </summary>
        /// <param name="projectType"></param>
        /// <param name="username"></param>
        /// <returns></returns>
        /// Modify: Hoang Van Tai, move Helper to RoleManager; string projectType ==  ApplicationName: Van Tai bỏ 
        public Dictionary<Guid, Role> GetRolesForUser2(string username)
        {
            try
            {
                Dictionary<Guid, Role> list_roles = new Dictionary<Guid, Role>();
                List<string> roles = new List<string>();
                List<string> roleforproject = new List<string>();

                //Get all role available for project
                var rfps = from rfp in this.mdb.AHSAspnetRoles
                           where rfp.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()
                           select rfp;

                foreach (var it in rfps)
                {
                    roleforproject.Add(it.Rolename);
                }

                //Check role in system
                List<string> roleinsystem = Roles.Provider.GetRolesForUser(username).ToList();

                foreach (var it in roleinsystem)
                {
                    if (roleforproject.Contains(it)) roles.Add(it);
                }

                //Check role user in project
                var uips = from uip in this.mdb.AHSUserInProjects
                           where (uip.Status.HasValue && uip.Status.Value == 1) && (uip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()) && (uip.AHSAspnetMembership_Userid.AHSAspnetUser.Username.ToLower() == username.ToLower()) && (uip.Roleid.HasValue)
                           select uip.AHSAspnetRole.Rolename;

                foreach (var uip in uips)
                {
                    if (!roles.Contains(uip)) roles.Add(uip);
                }

                //Check role user in project via organization
                var oips = from oip in this.mdb.AHSOrganizationInProjects
                           join uio in this.mdb.AHSUsersInOrganizations on oip.Orgid equals uio.OrgId
                           where (oip.Status.HasValue && oip.Status.Value == 1) && (uio.Status.HasValue && uio.Status.Value == 1) && (oip.AHSMainProject.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()) && (uio.AHSAspnetUser.Username.ToLower() == username.ToLower()) && (oip.Roleid.HasValue)
                           select oip.AHSAspnetRole.Rolename;

                foreach (var oip in oips)
                {
                    if (!roles.Contains(oip)) roles.Add(oip);
                }

                //Check role user in organ empowering
                var rios = from rio in this.mdb.AHSUsersInOrganizations
                           where (rio.Status.HasValue && rio.Status.Value == 1) && (rio.AHSAspnetUser.Username.ToLower() == username.ToLower()) && (rio.AHSOrganization.OrgType == 1) && (rio.AHSOrganization.RoleID.HasValue)
                           select rio.AHSOrganization.AHSAspnetRole.Rolename;

                foreach (var rio in rios)
                {
                    if (!roles.Contains(rio) && roleforproject.Contains(rio)) roles.Add(rio);
                }

                //Get role for project
                var lst_roles = from role in this.mdb.AHSAspnetRoles
                                where (!role.Isrolepermit.HasValue || !role.Isrolepermit.Value) && (role.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower())
                                select role;

                foreach (var role in lst_roles)
                {
                    if (roles.Contains(role.Rolename))
                    {
                        Role r = new Role();

                        r.RoleId = role.Roleid;
                        r.ApplicationName = this.ApplicationName;
                        r.RoleName = role.Rolename;
                        r.RoleDisplay = role.Roledisplay;

                        if (role.Roletype.HasValue)
                            r.RoleType = role.Roletype.Value;
                        else r.RoleType = 0;

                        if (role.Projecttype.HasValue)
                            r.ProjectType = role.Projecttype.Value;
                        else r.ProjectType = 0;

                        list_roles.Add(role.Roleid, r);
                    }
                }

                return list_roles;
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] RoleManager.GetRolesForUser2 error {0}", ex);

                return null;
            }
        }

        /// <summary>
        /// Grant permission
        /// </summary>
        /// <param name="grant"></param>
        /// <returns></returns>
        public bool GrantPermission(Guid roleID, int permissionID, bool grant)
        {
            try
            {
                var role_permission = from rp in this.mdb.AHSRolePermissions where rp.PermissionID == permissionID && rp.RoleID == roleID select rp;

                if (grant)
                {
                    //Grant
                    if ((role_permission == null) || (role_permission.Any() == false))
                    {
                        AHSRolePermission rp = new AHSRolePermission();

                        rp.PermissionID = permissionID;
                        rp.RoleID = roleID;

                        this.mdb.AHSRolePermissions.InsertOnSubmit(rp);

                        this.mdb.SubmitChanges();
                    }
                }
                else
                {
                    //Remove
                    if ((role_permission != null) && (role_permission.Any()))
                    {
                        this.mdb.AHSRolePermissions.DeleteAllOnSubmit(role_permission);
                        this.mdb.SubmitChanges();
                    }
                }

                return true;
            }
            catch (Exception ex)
            {
                this.mdb.RejectChanges();
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] AHSService.Library.Manager.RoleManager.GrantPermission error {0}", ex);

                return false;
            }
        }

        /// <summary>
        /// Add role for project type
        /// </summary>
        /// <param name="projectTypeName"></param>
        /// <param name="roleNmae"></param>
        /// <returns></returns>
        public bool AddRoleForProjectType(string projectTypeName, string roleName, string roleDisplay, int? Priority = null)
        {
            try
            {
                if (!Roles.RoleExists(roleName))
                {
                    //the role is not exist => create role
                    Roles.CreateRole(roleName);
                    //get projecttype for role
                    var pt_for_role = from pts in this.mdb.AHSProjectTypes
                                      where pts.ApplicationName == this.ApplicationName && pts.Name == projectTypeName
                                      select pts;
                    int? pt = null;
                    if ((pt_for_role != null) && (pt_for_role.Any()))
                    {
                        var max_priority = from pr in this.mdb.AHSAspnetRoles
                                           where pr.AHSProjectType.ApplicationName == this.ApplicationName 
                                           && pr.AHSProjectType.Name == projectTypeName && pr.Priority !=null
                                           group pr by 1 into g
                                           select g.Max(pr => pr.Priority.Value);
                        int priority = -1;

                        if (max_priority != null && max_priority.Any())
                        {
                            priority = max_priority.FirstOrDefault();
                        }

                        pt = pt_for_role.FirstOrDefault().Id;

                        //update the role information
                        var info = from r in this.mdb.AHSAspnetRoles
                                   where r.Rolename == roleName
                                   select r;
                        if ((info != null) && info.Any())
                        {
                            var ru = info.FirstOrDefault();
                            ru.Roledisplay = roleDisplay;
                            ru.Isrolepermit = false;
                            ru.Roletype = 1;
                            ru.Projecttype = pt;
                            if (Priority.HasValue)
                            {
                                ru.Priority = Priority.Value;
                            }
                            else
                            {
                                ru.Priority = priority + 1;
                            }
                            this.mdb.SubmitChanges();
                        }
                    }

                }

                return true;
            }
            catch (Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] AHSService.Library.Manager.RoleManager.AddRoleForProjectType error {0}", ex);

                return false;
            }
        }

        /// <summary>
        /// Author: Bui Dinh Tuong
        /// </summary>
        /// <returns></returns>
        public List<Role> GetRoleList(string username, bool ispm = false, int prjtype = 0)
        {
            try
            {
                
                List<Role> ret = new List<Role>();

                UserManager um = new UserManager(this.ApplicationName);
                Guid uUserId = um.GetUserID(username);
                bool isAdmin =  MembershipHelper.CheckAdmin(username);
                

                //List<int> lr = um.GetListRoleTypeSelf();
                //List<Guid> lra = um.GetListRoleAdminSelf();
                //List<ProjectTypeRoleType> lpta = um.GetListProjectTypeAndRoleAdminSelf();

                if (ispm)
                {
                    if (isAdmin)
                    {
                        //Get role Permit manager
                        var roles = (from r in this.mdb.AHSAspnetRoles
                                    where (r.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower())        
                                    orderby r.Priority descending, r.Rolename ascending
                                    select r).Distinct();

                        foreach (var item in roles)
                        {
                            ret.Add(new Role(item.Roleid, this.ApplicationName,item.Rolename, item.Roledisplay, item.Roletype,item.Projecttype,item.Isrolepermit,item.Adminforprojectype));
                        }
                    }
                    else
                    {
                        //Get role Permit manager
                        var roles = (from r in this.mdb.AHSAspnetRoles
                                    where (r.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower())
                                    orderby r.Priority descending, r.Rolename ascending
                                    select r).Distinct();

                        foreach (var item in roles)
                        {
                            ret.Add(new Role(item.Roleid, this.ApplicationName, item.Rolename, item.Roledisplay, item.Roletype, item.Projecttype, item.Isrolepermit, item.Adminforprojectype));
                        }
                    }
                }
                else if (prjtype != 0)
                {
                    if (isAdmin)
                    {
                        //Get role of prjtype
                        var roles = (from r in this.mdb.AHSAspnetRoles
                                    where  (r.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()) && 
                                        r.Projecttype == prjtype
                                    orderby r.Priority descending, r.Rolename ascending
                                    select r).Distinct();

                        foreach (var item in roles)
                        {
                            ret.Add(new Role(item.Roleid, this.ApplicationName, item.Rolename, item.Roledisplay, item.Roletype, item.Projecttype, item.Isrolepermit, item.Adminforprojectype));
                        }
                    }
                    else
                    {
                        //Get role of prjtype
                        var roles = (from r in this.mdb.AHSAspnetRoles
                                    where (!r.Isrolepermit.HasValue || !r.Isrolepermit.Value) && r.Projecttype.HasValue && 
                                    (r.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()) && 
                                    r.Roletype.HasValue && r.Projecttype == prjtype
                                    orderby r.Priority descending, r.Rolename ascending
                                    select r).Distinct();

                        List<ProjectTypeRoleType> lpta = um.GetListProjectTypeAndRoleAdminSelf(uUserId, isAdmin);
                        foreach (var item in roles)
                        {
                            if (lpta.Contains(new ProjectTypeRoleType(item.Projecttype.Value, item.Roletype.Value)))
                                ret.Add(new Role(item.Roleid, this.ApplicationName, item.Rolename, item.Roledisplay, item.Roletype, item.Projecttype, item.Isrolepermit, item.Adminforprojectype));
                        }
                    }
                }

                return ret;
            }
            catch (System.Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] AHSService.Library.Manager.RoleManager.GetRoleList error {0}", ex);

                return null;
            }
        }

        /// <summary>
        /// Author: Le Anh Phong
        /// </summary>
        /// <returns></returns>
        public List<Role> GetAllRole()
        {
            try
            {
                List<Role> ret = new List<Role>();

                var roles = (from r in this.mdb.AHSAspnetRoles
                            where (r.AHSProjectType.ApplicationName.ToLower() == this.ApplicationName.ToLower()) 
                            orderby r.Priority descending, r.Rolename ascending
                            select r).Distinct();
                foreach (var item in roles)
                {
                    ret.Add(new Role(item.Roleid, this.ApplicationName, item.Rolename, item.Roledisplay, item.Roletype, item.Projecttype, item.Isrolepermit, item.Adminforprojectype));
                }

                return ret;
            }
            catch (System.Exception ex)
            {
                Logger.Log.ErrorFormat("[" + this.ApplicationName + "] AHSService.Library.Manager.RoleManager.GetAllRole error {0}", ex);

                return null;
            }
        }
    }
}